package pl.edu.pw.ee.buildcity.scheduler.strategies;

import org.apache.log4j.Logger;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Configurable;
import pl.edu.pw.ee.buildcity.commons.exceptions.BuildCityRuntimeException;
import pl.edu.pw.ee.buildcity.domain.BuildStatus;
import pl.edu.pw.ee.buildcity.scheduler.BuildContext;
import pl.edu.pw.ee.buildcity.scheduler.BuildPostProcessing;
import pl.edu.pw.ee.buildcity.scm.subversion.SubversionService;
import pl.edu.pw.ee.buildcity.services.BuildActivityService;
import pl.edu.pw.ee.buildcity.services.api.BuilderService;

import javax.annotation.Resource;
import java.io.File;

/**
 * @author Mateusz
 * @since 2010-02-28
 */
@Configurable
public abstract class BuildStrategy {

	protected final Logger log = Logger.getLogger(getClass().getCanonicalName());

	@Resource(name = "buildActivityService")
	protected BuildActivityService buildActivityService;

	@Resource(name = "subversionService")
	protected SubversionService svnService;

	@Resource(name = "mavenBuilder")
	private BuilderService mavenBuilder;

	@Resource(name = "buildPostProcessing")
	protected BuildPostProcessing buildPostProcessing;

	protected final BuildContext buildCtx;
	protected File workingCopy;

	public BuildStrategy(BuildContext context, File workingCopy) {
		this.buildCtx = context;
		this.workingCopy = workingCopy;
	}

	/**
	 * Executes chain of activities related to build, depending on particular strategy:
	 * <ul><li>actions before build (registering activity start, collecting list of commits)</li>
	 * <li>core build process</li>
	 * <li>actions after build (registering activity finish with proper result, performing notifications etc.)</li></ul>
	 * <p/>
	 * <p>Only core build process (p.2) exceptions are handled and cause build to be considered as {@link pl.edu.pw.ee.buildcity.domain.BuildStatus#FAILED}. <br />
	 * Other exceptions (like gg or email service unavailable) are not handled and they are propagated to Quartz engine..
	 * </p>
	 * <p>If needed, additional actions (like notifying BuildCity admin etc) can be made in
	 * {@link pl.edu.pw.ee.buildcity.scheduler.listeners.BuildJobExecutionListener#jobWasExecuted(org.quartz.JobExecutionContext, org.quartz.JobExecutionException)}.
	 * </p>
	 */
	public void execute() {
		preProcess();
		try {
			performBuild();
		} catch (BuildCityRuntimeException e) {
			log.error("Exception during build occurred: " + e.getMessage());
			buildCtx.considerAsFailed(e);
		} catch (Exception e) {
			log.error("Fatal error during build occurred: " + e.getMessage(), e);
			buildCtx.considerAsFailed(e);
		}
		postProcess();
	}

	/**
	 * Actions made by particular strategy before running build
	 */
	protected abstract void preProcess();

	/**
	 * Actions made by particular strategy when running build
	 *
	 * @throws JobExecutionException
	 */
	protected abstract void performBuild() throws BuildCityRuntimeException;

	/**
	 * Actions made by particular strategy after running build
	 */
	protected abstract void postProcess();

	protected final void runMaven2Build() throws BuildCityRuntimeException {
		String buildCommand = buildCtx.getBuildCommand();
		BuildStatus status = mavenBuilder.build(workingCopy, buildCommand);
		if (status == BuildStatus.FAILED) {
			throw new BuildCityRuntimeException("Build status ended with " + BuildStatus.FAILED + " status!");
		}
	}

	@Override
	public String toString() {
		return getClass().getCanonicalName();
	}

	//TODO Remove it! It's only for checking whether @Configurable work properly (class was weaved)

	public BuildActivityService getBuildActivityService() {
		return buildActivityService;
	}
}
